package org.optaplanner.examples.apsplanning.app;

import org.optaplanner.core.api.solver.Solver;
import org.optaplanner.core.api.solver.SolverFactory;
import org.optaplanner.examples.apsplanning.config.ApsPlanningDBConfig;
import org.optaplanner.examples.apsplanning.domain.ApsPlanningSolution;
import org.optaplanner.examples.apsplanning.domain.BomTask;
import org.optaplanner.examples.apsplanning.domain.Device;
import org.optaplanner.examples.apsplanning.domain.Process;
import org.optaplanner.examples.apsplanning.service.BomTaskService;
import org.optaplanner.examples.apsplanning.service.DeviceService;
import org.optaplanner.examples.apsplanning.service.ProcessService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;

/**
 * @author andaolong
 * @time 2021/3/27-9:08
 * @describe aps排程项目的入口
 */
public class ApsPlanningMain {

    public static void main(String[] args) {

        //通过配置的xml文件，构造求解器
        SolverFactory<ApsPlanningSolution> solverFactory = SolverFactory.createFromXmlResource(
                "org/optaplanner/examples/apsplanning/solver/apsplanningSolverConfig.xml");
        Solver<ApsPlanningSolution> solver = solverFactory.buildSolver();
        System.out.println("通过配置的xml文件，构造好了求解器");


        //这里将初始数据从数据库载入
        ApsPlanningSolution unsolvedApsSolution = getUnassignment();
        System.out.println("将初始数据从数据库载入");

        //启动引擎求解问题
        ApsPlanningSolution solvedCloudBalance = solver.solve(unsolvedApsSolution);
        System.out.println("通过引擎求解问题");

        //输出每个bom节点分配的设备
        System.out.println(
                "\nSolved apsPlanning:\n"
                        + "求解结果为:\n"
                        + toDisplayString(solvedCloudBalance));
        //打印出设备上的任务链
        printTheDeviceChain(solvedCloudBalance);

        System.out.println("最后分数为：" + solvedCloudBalance.getScore());
    }

    //输出每个bom节点分配的设备
    public static String toDisplayString(ApsPlanningSolution apsPlanningSolution) {
        //新建一个StringBuilder，相对于String的好处是可以持续增加字符串长度而不用重新分配空间
        StringBuilder displayString = new StringBuilder();
        //遍历bomTask节点，获取到给每个bom节点分配的机器
        for (BomTask bomTask : apsPlanningSolution.getBomTaskList()) {
            Device device = bomTask.getDevice();
            //然后将分配的机器输出
            displayString.append("  ")
                    .append("bom节点[" + bomTask.getLabel()).append("] 分配的设备是-------> ")
                    .append(device == null ? null : device.getLabel()).append("\n");
        }
        return displayString.toString();
    }

    //打印出设备上的任务链
    public static String printTheDeviceChain(ApsPlanningSolution apsPlanningSolution) {

        //遍历每个设备，设备是锚，是每条排程链的起始点
        for (Device device : apsPlanningSolution.getDeviceList()) {

            System.out.println("设备[" + device.getDeviceId() + "]上的bomTask列表如下\n");
            //设备是每条链的锚，从锚向后遍历获取到分配到设备上的bomTask列表
            int orderNumber = 1;
            BomTask bomTaskTemp = device.getNextBomTask();

            if(bomTaskTemp==null){
                System.out.println("本设备上没有分配bomTask任务\n");
            }else{
                while (bomTaskTemp != null) {
                    System.out.println("\t\t"+orderNumber + ".[" + bomTaskTemp.getBomName() + "="+bomTaskTemp.getProcess().getProcessName()+"]=====开始时间为："+bomTaskTemp.getStartTime()+"minute\n");
                    bomTaskTemp = bomTaskTemp.getNextBomTask();
                    orderNumber = orderNumber + 1;
                }
            }        }
        return "任务链打印完毕";
    }


    //从数据库获取到computer和process的初始数据填入solution中
    protected static ApsPlanningSolution getUnassignment() {

        ApplicationContext context =
                new AnnotationConfigApplicationContext(ApsPlanningDBConfig.class);

        DeviceService deviceService = context.getBean("deviceService", DeviceService.class);
        BomTaskService bomTaskService = context.getBean("bomTaskService", BomTaskService.class);
        ProcessService processService = context.getBean("processService", ProcessService.class);

        List<Device> deviceList = deviceService.getDeviceList();
        List<BomTask> bomTaskList = bomTaskService.getBomTaskList();
        List<Process> processList = processService.getAllProcess();

        ApsPlanningSolution unAssignment = new ApsPlanningSolution(0, deviceList, bomTaskList,processList);

        return unAssignment;
    }
}

